/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_ttc8_logon.c                                   */
/*  NOTE      =                                                    */
/*  DATE      = 2014/10/15 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>

#include "frstr.h"
#include "frmem.h"
#include "frcomm.h"
#include "frlog.h"

#include "conntrack.h"
#include "frct_comm.h"

#include "../../ora_core.h"
#include "../../comm/ora_comm.h"
#include "../../comm/ora_util.h"
#include "../ora_mar_engine.h"
#include "../ora_ttc_proto.h"
#include "ora_ttc8_logon.h"

/*******************************************************************************
*  FUNC     :  解析0x0376和0x0373的logon请求包
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*           :  *p_st_hash_report                    (数据上报)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc8_logon_unpack_req(Conntrack *p_st_conn
                            , L7session_ora *p_st_sess
                            , L7_ora_packet *p_st_ora_packet)
{
    char *p_tmp = NULL;
    char c_tmp = 0;
    int i_tmp = 0;
    short s_tmp = 0;
    long long ll_tmp = 0LL;

    char c_user_flag = 0;
    int i_user_len = 0;
    long long keyvallist_size = 0LL;
    int i_user_flag_pktoffset = 0;
    int i_detect_ptr_count = 0;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // seqNumber
        goto error;

    // 记录当前的offset
    i_user_flag_pktoffset = bytebuff_getPosition(p_st_ora_packet->p_st_packet);

detect_nullptr:
    if (i_detect_ptr_count != 0)
    {
        p_st_ora_packet->fragment_state = APM_ORA_FRAGMENT_INIT;
        ora_free((void **) &(p_st_sess->p_username));
        p_st_sess->i_detect_ptr_succ = FR_NO;
        if (p_st_sess->i_use_oci == FR_NO)
            goto error;
        else if (i_detect_ptr_count > 2)
        {
            ORA_PRINT_DBG("Can not detect PTR setting.\n");
            ORA_FRLOG_ERROR("Can not detect PTR setting.");
            goto error;
        }
    }
    i_detect_ptr_count++;

    if (p_st_sess->i_use_oci == FR_YES)
    {
        if (p_st_sess->i_ptr_len == APM_ORA_FLAG_UNSET)
            p_st_sess->i_ptr_len = APM_ORA_PTR_LEN_4;
        else if (p_st_sess->i_detect_ptr_succ == FR_NO)
        {
            if (p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_4)
                p_st_sess->i_ptr_len = APM_ORA_PTR_LEN_1;
            else if (p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_1)
                p_st_sess->i_ptr_len = APM_ORA_PTR_LEN_8;
            else if (p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_8)
                p_st_sess->i_ptr_len = APM_ORA_PTR_LEN_4;
        }
        ORA_PRINT_DBG("start to detect PTR setting，use p_st_sess->i_ptr_len = %d\n", p_st_sess->i_ptr_len);
    }

    // 重新设置offset
    if (bytebuff_setPosition(p_st_ora_packet->p_st_packet, i_user_flag_pktoffset) != FR_SUCC)
        goto error;

    if (ora_mar_unmarshalO2U(p_st_sess, p_st_ora_packet, &c_user_flag) != FR_SUCC)    // user.flag
        goto detect_nullptr;
    ORA_PRINT_DBG("c_user_flag:[%d]\n", c_user_flag);

    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_user_len) != FR_SUCC)     // user.length
        goto detect_nullptr;
    ORA_PRINT_DBG("i_user_len:[%d]\n", i_user_len);

    if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_tmp) != FR_SUCC)         // logonMode
        goto detect_nullptr;

    if (ora_mar_unmarshalO2U(p_st_sess, p_st_ora_packet, &c_tmp) != FR_SUCC)    // PTR
        goto detect_nullptr;

    if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &keyvallist_size) != FR_SUCC)          // keyValList.size
        goto detect_nullptr;
    ORA_PRINT_DBG("keyvallist_size:[%lld]\n", keyvallist_size);
    if (p_st_sess->i_use_special_field == FR_YES && p_st_sess->i_send_typerep == FR_NO && p_st_sess->c_ttc_version >= 4 && p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_8)
    {
        ORA_PRINT_INFO("logon skip OCI4\n");
        if (ora_mar_skip(p_st_ora_packet, 4) != FR_SUCC)
            goto error;
    }

    if (ora_mar_unmarshalO2U(p_st_sess, p_st_ora_packet, &c_tmp) != FR_SUCC)    // PTR
        goto detect_nullptr;
    if (ora_mar_unmarshalO2U(p_st_sess, p_st_ora_packet, &c_tmp) != FR_SUCC)    // PTR
        goto detect_nullptr;

    if (c_user_flag == APM_ORA_PTR && i_user_len > 0)
    {
        if (ora_mar_unmarshalCHR(i_user_len, p_st_sess, p_st_ora_packet, &p_tmp, &i_tmp) == FR_SUCC)  // user
        {
            ora_free((void **) &(p_st_sess->p_username));
            if ((p_st_sess->p_username = (char *) ora_malloc((i_tmp + 1) * sizeof(char), bytebuff_remaining(p_st_ora_packet->p_st_packet) + 1)) == NULL)
            {
                ORA_MALLOCK_ERR;
                ora_free((void **) &p_tmp);
                goto error;
            }
            memcpy(p_st_sess->p_username, p_tmp, (size_t) i_tmp);
            p_st_sess->p_username[i_tmp] = '\0';
            ORA_PRINT_DBG("username:[%s]\n", p_st_sess->p_username);
            ora_free((void **) &p_tmp);
        }
        else
            goto detect_nullptr;
    }

    if (ora_mar_unmarshalKEYVAL((int) keyvallist_size, p_st_sess, p_st_ora_packet) != FR_SUCC)
        goto detect_nullptr;

    if (bytebuff_remaining(p_st_ora_packet->p_st_packet) != 0)
        goto detect_nullptr;

    p_st_sess->i_detect_ptr_succ = FR_YES;
    p_st_sess->i_ttc8_stmt_resp_oac_skipaftervsn = p_st_sess->c_ttc_version >= 4 && p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_8 ? FR_YES : FR_NO;
    ORA_PRINT_SESS(p_st_sess);

    return FR_SUCC;
error:
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  RPC -> readRPA
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc8_logon_read_RPA(Conntrack *p_st_conn
                            , L7session_ora *p_st_sess
                            , L7_ora_packet *p_st_ora_packet)
{
    int i_out_NbPairs = 0;                          // outNbPairs

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_out_NbPairs) != FR_SUCC)
        goto error;

    ORA_PRINT_DBG("outNbPairs:[%d]\n", i_out_NbPairs);
    if (ora_mar_unmarshalKEYVAL(i_out_NbPairs, p_st_sess, p_st_ora_packet) != FR_SUCC)
        goto error;

    return FR_SUCC;
error:
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  设置RPC函数指针
*  ARGS     :  *p_st_ora_rpc_recv  (函数指针结构体)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void ora_ttc8_logon_set_rpc_func(Ora_rpc_recv *p_st_ora_rpc_recv)
{
    p_st_ora_rpc_recv->read_RPA = &ora_ttc8_logon_read_RPA;
    return;
}
